{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "initial_id",
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": "# 获取大模型"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-10-25T03:12:48.117955Z",
     "start_time": "2025-10-25T03:12:47.496808Z"
    }
   },
   "cell_type": "code",
   "source": [
    "import dotenv\n",
    "import os\n",
    "\n",
    "from langchain_openai import ChatOpenAI, OpenAI\n",
    "\n",
    "dotenv.load_dotenv()\n",
    "\n",
    "os.environ[\"OPENAI_API_KEY\"] = os.getenv(\"OPENAI_API_KEY\")\n",
    "os.environ[\"OPENAI_API_BASE\"] = os.getenv(\"OPENAI_BASE_URL\")\n",
    "CHAT_MODEL = ChatOpenAI(\n",
    "    model=\"gpt-4o-mini\"\n",
    ")\n",
    "\n",
    "llm = OpenAI(\n",
    "    model=\"gpt-4o-mini\",\n",
    ")"
   ],
   "id": "34ddd8048d4edce8",
   "outputs": [],
   "execution_count": 2
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# Model I/O之Output Parsers",
   "id": "2da091180abf9f8"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "## 字符串解析器 StrOutputParser",
   "id": "783f48d7ba5607a2"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-10-25T03:48:18.361503Z",
     "start_time": "2025-10-25T03:48:16.632098Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from langchain_core.messages import SystemMessage, HumanMessage\n",
    "from langchain_core.output_parsers import StrOutputParser\n",
    "\n",
    "messages = [\n",
    "    SystemMessage(\"将一下内容从英文转为中文\"),\n",
    "    HumanMessage(\"It's a nice day today.\")\n",
    "]\n",
    "\n",
    "print(\"=== 调用大模型结果 ===\")\n",
    "result = CHAT_MODEL.invoke(messages)\n",
    "print(type(result))\n",
    "print(result)\n",
    "\n",
    "print(\"=== 字符串解析器 ===\")\n",
    "xml_parser = StrOutputParser()\n",
    "parsed_result = xml_parser.invoke(result)\n",
    "print(type(parsed_result))\n",
    "print(parsed_result)"
   ],
   "id": "b37300d6f18b6477",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "=== 调用大模型结果 ===\n",
      "<class 'langchain_core.messages.ai.AIMessage'>\n",
      "content='今天是个好天气。' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 7, 'prompt_tokens': 25, 'total_tokens': 32, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_efad92c60b', 'id': 'chatcmpl-CUPYIxtri0EBR3aCIksCQ7YXpi91D', 'service_tier': None, 'finish_reason': 'stop', 'logprobs': None} id='run--123802e3-3f82-420d-bd8c-540fba1eb524-0' usage_metadata={'input_tokens': 25, 'output_tokens': 7, 'total_tokens': 32, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}\n",
      "=== 字符串解析器 ===\n",
      "<class 'str'>\n",
      "今天是个好天气。\n"
     ]
    }
   ],
   "execution_count": 3
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "## JSON解析器\n",
    "**json格式字符串解析为字典**"
   ],
   "id": "c528c3fc56c562aa"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "### 手动提示使用JSON解析器格式",
   "id": "d5e968cbee9eb4f5"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-10-25T05:56:33.906353Z",
     "start_time": "2025-10-25T05:56:31.391450Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "from langchain_core.output_parsers import JsonOutputParser\n",
    "\n",
    "chat_prompt_template = ChatPromptTemplate.from_messages([\n",
    "    (\"system\", \"你是一个靠谱的{role}\"),\n",
    "    (\"human\", \"{question}\")\n",
    "])\n",
    "\n",
    "format_prompt = chat_prompt_template.format_messages(role=\"人工智能专家\",\n",
    "                                                     question=\"人工智能用英文怎么说？问题用q表示，答案用a表示，返回一个JSON格式\")\n",
    "print(format_prompt)\n",
    "\n",
    "# 方式一\n",
    "print(\"========= 方式一调用 ==========\")\n",
    "print(\"===大模型调用===\")\n",
    "result = CHAT_MODEL.invoke(format_prompt)\n",
    "print(type(result))\n",
    "print(result)\n",
    "print(\"=== JSON解析器（解析为dict） ===\")\n",
    "xml_parser = JsonOutputParser()\n",
    "parse_result = xml_parser.invoke(result)\n",
    "print(type(parse_result))\n",
    "print(parse_result)\n",
    "\n",
    "# 方式二\n",
    "print(\"========= 方式二调用 ==========\")\n",
    "chain = chat_prompt_template | CHAT_MODEL | xml_parser\n",
    "chain.invoke({\"role\": \"人工智能专家\", \"question\": \"人工智能用英文怎么说？问题用q表示，答案用a表示，返回一个JSON格式\"})"
   ],
   "id": "5d3b4e74926e5355",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[SystemMessage(content='你是一个靠谱的人工智能专家', additional_kwargs={}, response_metadata={}), HumanMessage(content='人工智能用英文怎么说？问题用q表示，答案用a表示，返回一个JSON格式', additional_kwargs={}, response_metadata={})]\n",
      "========= 方式一调用 ==========\n",
      "===大模型调用===\n",
      "<class 'langchain_core.messages.ai.AIMessage'>\n",
      "content='```json\\n{\\n  \"q\": \"人工智能怎么用英文说？\",\\n  \"a\": \"Artificial Intelligence\"\\n}\\n```' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 28, 'prompt_tokens': 40, 'total_tokens': 68, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_efad92c60b', 'id': 'chatcmpl-CURYNbbdXH1BkPLkO3QRfLpN75jiq', 'service_tier': None, 'finish_reason': 'stop', 'logprobs': None} id='run--acb67f7b-29f4-4414-b39f-290f11fa7fe0-0' usage_metadata={'input_tokens': 40, 'output_tokens': 28, 'total_tokens': 68, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}\n",
      "=== JSON解析器 ===\n",
      "<class 'dict'>\n",
      "{'q': '人工智能怎么用英文说？', 'a': 'Artificial Intelligence'}\n",
      "========= 方式二调用 ==========\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'q': '人工智能用英文怎么说？', 'a': 'Artificial Intelligence'}"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 8
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "### 使用 get_format_instructions 自动生成告诉语言模型如何格式化输出的指令",
   "id": "5e986d867f34abb1"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-10-25T07:24:08.062136Z",
     "start_time": "2025-10-25T07:24:06.343734Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from langchain_core.prompts import PromptTemplate\n",
    "from langchain_core.output_parsers import JsonOutputParser\n",
    "\n",
    "joke_query = \"告诉我一个笑话。\"\n",
    "\n",
    "xml_parser = JsonOutputParser()\n",
    "\n",
    "prompt = PromptTemplate(\n",
    "    template=\"回答用户的查询.\\n{format_instructions}\\n{query}\",\n",
    "    input_variables=[\"query\"],\n",
    "    partial_variables={\"format_instructions\": xml_parser.get_format_instructions()},\n",
    ")\n",
    "print(\"========== formatPrompt ===========\")\n",
    "formatPrompt = prompt.invoke({\"query\": \"给我讲一个笑话\"})\n",
    "print(formatPrompt)\n",
    "\n",
    "print(\"=========== 大模型调用 =============\")\n",
    "chain = prompt | CHAT_MODEL | xml_parser\n",
    "output = chain.invoke({\"query\": \"给我讲一个笑话\"})\n",
    "print(type(output))\n",
    "print(output)"
   ],
   "id": "163d4d2c683a304",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "========== formatPrompt ===========\n",
      "text='回答用户的查询.\\nReturn a JSON object.\\n给我讲一个笑话'\n",
      "=========== 大模型调用 =============\n",
      "<class 'dict'>\n",
      "{'joke': '为什么程序员总是把圣诞节和万圣节混淆？', 'punchline': '因为 DEC 25 = OCT 31!'}\n"
     ]
    }
   ],
   "execution_count": 25
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "## XML解析器\n",
    "**xml格式字符串解析为字典**"
   ],
   "id": "7620825e9925d92e"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-10-25T06:59:07.614188Z",
     "start_time": "2025-10-25T06:59:03.060120Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from langchain_core.output_parsers import XMLOutputParser\n",
    "from langchain_core.prompts import PromptTemplate\n",
    "\n",
    "xml_parser = XMLOutputParser()\n",
    "\n",
    "prompt_template = PromptTemplate.from_template(\n",
    "    \"{query}\\n{format_instructions}\",\n",
    "    partial_variables={\"format_instructions\": xml_parser.get_format_instructions()},\n",
    ")\n",
    "\n",
    "format_prompt = prompt_template.format(query=\"生成汤姆·汉克斯的简短电影记录,使用中文回复\")\n",
    "print(f\"========格式化后提示词内容:============\\n{type(format_prompt)}\\n{format_prompt}\\n\")\n",
    "result = CHAT_MODEL.invoke(format_prompt)\n",
    "print(f\"========大模型调用响应内容:========{type(result.content)}\\n{result.content}\\n\")\n",
    "parser_result = xml_parser.invoke(result)\n",
    "print(f\"========XML解析器解析结果:========{type(parse_result)}\\n{parser_result}\")"
   ],
   "id": "18bb312359e58414",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "========格式化后提示词内容:============\n",
      "<class 'str'>\n",
      "生成汤姆·汉克斯的简短电影记录,使用中文回复\n",
      "The output should be formatted as a XML file.\n",
      "1. Output should conform to the tags below.\n",
      "2. If tags are not given, make them on your own.\n",
      "3. Remember to always open and close all the tags.\n",
      "\n",
      "As an example, for the tags [\"foo\", \"bar\", \"baz\"]:\n",
      "1. String \"<foo>\n",
      "   <bar>\n",
      "      <baz></baz>\n",
      "   </bar>\n",
      "</foo>\" is a well-formatted instance of the schema.\n",
      "2. String \"<foo>\n",
      "   <bar>\n",
      "   </foo>\" is a badly-formatted instance.\n",
      "3. String \"<foo>\n",
      "   <tag>\n",
      "   </tag>\n",
      "</foo>\" is a badly-formatted instance.\n",
      "\n",
      "Here are the output tags:\n",
      "```\n",
      "None\n",
      "```\n",
      "\n",
      "========大模型调用响应内容:========<class 'str'>\n",
      "```xml\n",
      "<电影记录>\n",
      "    <演员>\n",
      "        <姓名>汤姆·汉克斯</姓名>\n",
      "        <出生日期>1956-07-09</出生日期>\n",
      "        <国籍>美国</国籍>\n",
      "    </演员>\n",
      "    <电影>\n",
      "        <标题>阿甘正传</标题>\n",
      "        <年份>1994</年份>\n",
      "        <角色>阿甘</角色>\n",
      "        <导演>罗伯特·泽米吉斯</导演>\n",
      "    </电影>\n",
      "    <电影>\n",
      "        <标题>拯救大兵瑞恩</标题>\n",
      "        <年份>1998</年份>\n",
      "        <角色>米勒上尉</角色>\n",
      "        <导演>史蒂文·斯皮尔伯格</导演>\n",
      "    </电影>\n",
      "    <电影>\n",
      "        <标题>费城故事</标题>\n",
      "        <年份>1993</年份>\n",
      "        <角色>安德鲁·贝克特</角色>\n",
      "        <导演>乔纳森·德梅</导演>\n",
      "    </电影>\n",
      "    <电影>\n",
      "        <标题>武汉热水器</标题>\n",
      "        <年份>2022</年份>\n",
      "        <角色>记者</角色>\n",
      "        <导演>未知</导演>\n",
      "    </电影>\n",
      "</电影记录>\n",
      "```\n",
      "\n",
      "========XML解析器解析结果:========<class 'dict'>\n",
      "{'电影记录': [{'演员': [{'姓名': '汤姆·汉克斯'}, {'出生日期': '1956-07-09'}, {'国籍': '美国'}]}, {'电影': [{'标题': '阿甘正传'}, {'年份': '1994'}, {'角色': '阿甘'}, {'导演': '罗伯特·泽米吉斯'}]}, {'电影': [{'标题': '拯救大兵瑞恩'}, {'年份': '1998'}, {'角色': '米勒上尉'}, {'导演': '史蒂文·斯皮尔伯格'}]}, {'电影': [{'标题': '费城故事'}, {'年份': '1993'}, {'角色': '安德鲁·贝克特'}, {'导演': '乔纳森·德梅'}]}, {'电影': [{'标题': '武汉热水器'}, {'年份': '2022'}, {'角色': '记者'}, {'导演': '未知'}]}]}\n"
     ]
    }
   ],
   "execution_count": 24
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "## 列表解析器\n",
    "利用此解析器可以将模型的文本响应转换为一个用 逗号分隔的列表（List[str]） 。\n",
    "**逗号分隔的字符串 转 列表**"
   ],
   "id": "8313a70f52e7e1e9"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-10-25T07:44:32.001846Z",
     "start_time": "2025-10-25T07:44:29.964366Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from langchain_core.output_parsers import CommaSeparatedListOutputParser\n",
    "from langchain_core.prompts import PromptTemplate\n",
    "\n",
    "parser = CommaSeparatedListOutputParser()\n",
    "prompt_template = PromptTemplate.from_template(\n",
    "    template=\"生成5个关于{text}的列表.\\n{format_instructions}\",\n",
    "    partial_variables={\"format_instructions\": parser.get_format_instructions()},\n",
    ")\n",
    "\n",
    "formatMessage = prompt_template.format(text = \"水果\")\n",
    "print(f\"========格式化后提示词内容:============\\n{type(formatMessage)}\\n{formatMessage}\\n\")\n",
    "result = CHAT_MODEL.invoke(formatMessage)\n",
    "print(f\"========大模型调用响应内容:========{type(result.content)}\\n{result.content}\\n\")\n",
    "parser_result = parser.invoke(result)\n",
    "print(f\"========列表解析器解析结果:========{type(parser_result)}\\n{parser_result}\")"
   ],
   "id": "33b4e3a032a78676",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "========格式化后提示词内容:============\n",
      "<class 'str'>\n",
      "生成5个关于水果名称的列表.\n",
      "Your response should be a list of comma separated values, eg: `foo, bar, baz` or `foo,bar,baz`\n",
      "\n",
      "========大模型调用响应内容:========<class 'str'>\n",
      "苹果, 橙子, 香蕉, 葡萄, 草莓  \n",
      "菠萝, 猕猴桃, 西瓜, 桃子, 杏子  \n",
      "石榴, 蓝莓, 鳄梨, 柠檬, 荔枝  \n",
      "椰子, 李子, 木瓜, 柚子, 桔子  \n",
      "樱桃, 黑莓, 香瓜, 鲜枣, 杨梅  \n",
      "\n",
      "========列表解析器解析结果:========<class 'list'>\n",
      "['苹果', '橙子', '香蕉', '葡萄', '草莓  ', '菠萝', '猕猴桃', '西瓜', '桃子', '杏子  ', '石榴', '蓝莓', '鳄梨', '柠檬', '荔枝  ', '椰子', '李子', '木瓜', '柚子', '桔子  ', '樱桃', '黑莓', '香瓜', '鲜枣', '杨梅  ']\n"
     ]
    }
   ],
   "execution_count": 29
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "## 日期解析器",
   "id": "120b2190875a8f2e"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-10-25T07:47:52.698986Z",
     "start_time": "2025-10-25T07:47:51.679493Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "from langchain.output_parsers import DatetimeOutputParser\n",
    "\n",
    "chat_prompt = ChatPromptTemplate.from_messages([\n",
    "\t(\"system\",\"{format_instructions}\"),\n",
    "\t(\"human\", \"{request}\")\n",
    "])\n",
    "\n",
    "output_parser = DatetimeOutputParser()\n",
    "\n",
    "chain = chat_prompt | CHAT_MODEL | output_parser\n",
    "resp = chain.invoke({\"request\":\"中华人民共和国是什么时候成立的\", \"format_instructions\":output_parser.get_format_instructions()})\n",
    "print(type(resp))\n",
    "print(resp)"
   ],
   "id": "1cc9289a80398f85",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'datetime.datetime'>\n",
      "1949-10-01 00:00:00\n"
     ]
    }
   ],
   "execution_count": 31
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
